#ifndef OBSERVABLE_H_
#define OBSERVABLE_H_
#include <vector>
#include <algorithm>
#include "Observer.h"

namespace utils {

template <typename Object>
class Observer;

template <typename Object>
class Observable {
private:
	bool changed = false;
	std::vector<Observer<Object>* > obs;
public:
	Observable();
	~Observable();
	void addObserver(Observer<Object>* o);
	void deleteObserver(Observer<Object>* o);
	void notifyObservers();
	//void notifyObservers(Object);
	bool notifyObservers(Object);
	void deleteObservers();
	void setChanged();
	void clearChanged();
	bool hasChanged();
	int countObservers();
};

template <typename Object>
Observable<Object>::Observable() {}

template <typename Object>
Observable<Object>::~Observable() {}

template <typename Object>
void Observable<Object>::addObserver(Observer<Object>* o){
	obs.push_back(o);
}

template <typename Object>
void Observable<Object>::deleteObserver(Observer<Object>* o){
	obs.erase(std::remove(obs.begin(), obs.end(), o), obs.end());
}

template <typename Object>
void Observable<Object>::notifyObservers(){
	notifyObservers(nullptr);
}

//template <typename Object>
//void Observable<Object>::notifyObservers(Object arg){
//	if (!changed)
//		return;
//	clearChanged();
//
//	typename std::vector<Observer<Object>* >::iterator iter;
//	for (iter = obs.begin(); iter != obs.end(); ++iter)
//		(*iter)->update(this,arg);
//}

template <typename Object>
bool Observable<Object>::notifyObservers(Object arg){
	if (!changed){
		return false;
	}
	clearChanged();

	bool success = true;
	typename std::vector<Observer<Object>* >::iterator iter;
	for (iter = obs.begin(); iter != obs.end(); ++iter) {
		success = success & (*iter)->update(this,arg);
	}

	return success;
}


template <typename Object>
void Observable<Object>::deleteObservers(){
	obs.clear();
}


template <typename Object>
void Observable<Object>::setChanged(){
	changed = true;
}

template <typename Object>
void Observable<Object>::clearChanged(){
	changed = false;
}

template <typename Object>
bool Observable<Object>::hasChanged(){
	return changed;
}

template <typename Object>
int Observable<Object>::countObservers(){
	return obs.size();
}

} /* namespace utils */

#endif /* OBSERVABLE_H_ */
